#!/bin/sh
#    bl-places-pipemenu - an openbox places pipe menu
#    Copyright (C) 2010~2016  John Crawley <john@bunsenlabs.org>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.

#    NB The default shell (usually dash, not bash) is invoked
#    because it is faster.

# Usage: add
# <menu id="places" label="Places" execute="/path/to/bl-places-pipemenu ~/" />
# to your .config/openbox/menu.xml

# or, if you want the "recent files" menu incorporated at the top, use:
# <menu id="places" label="Places" execute="/path/to/bl-places-pipemenu --recent ~/" />
# make sure you have bl-recent-files-pipemenu somewhere, and enter its path below.

# path to your "recent files" script, if you want to incorporate it:
recent_script=/usr/bin/bl-recent-files-pipemenu

# Command to open folders at "Browse here..." - any file manager
open_folder_cmd=thunar
# Default command to open files with - others might be exo-open, gnome-open, thunar, pcmanfm...
default_open_cmd=xdg-open
# Text editor of choice
text_editor=geany

# function to open files with default open command, or alternative command for certain files
# - add other conditions to choice
open_file() {
    [ -x "$1" ] && exec "$text_editor" "$1"     # comment out this line if you don't want to edit executables instead of executing
    #[ -x "$1" ] && exec "x-terminal-emulator -e" "$1"     # uncomment this and comment out previous line to run executables in terminal instead of editing
    [ "${1##*.}" = desktop ] && exec "$text_editor" "$1"     # comment out this line if you don't want to edit .desktop files instead of executing
    exec "$default_open_cmd" "$1"     # use default open command if above conditions not satisfied
}

# extra dotfiles and directories to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated, surrounded by single quotes) or comment this line out, to taste:
shown_dotfiles='.config .local .Xresources .Xdefaults .bash_aliases .bashrc .inputrc .gtkrc-2.0.mine .profile .xsessionrc .xsession-errors'

# By default, this script will display directories separately, before files.
# To change this behaviour, see NOTE1, NOTE2 and NOTE3 below, near end of page.

HELP='    bl-places-pipemenu an Openbox Pipe Menu for showing a directory tree
    It should normally be called from an openbox menu.
Usage:
bl-places-pipemenu [options] [directory tree root]

Options:
    -h --help           show this message
    --open  <filepath>  open a file with configured default application
    (in this case the script will not output a menu)
    --recent            incorporate a "recent files" submenu

If a directory tree root is not specified, $HOME will be used.

Configuration:
/usr/bin/bl-places-pipemenu may be edited directly for system-wide changes,
or copied to ~/bin and edited there for per-user changes.

Editable variables and functions, at the top of the file:
recent_script       path to a script outputting an openbox pipemenu
open_folder_cmd     command to open folders - any file manager
default_open_cmd    default command to open files
text_editor         command to open text files
open_file()         open files, using commands above, or alternatives
shown_dotfiles      list of dotfiles to display (they are hidden by default)

By default, this script will display directories separately, before files.
To change this behaviour, see NOTE1, NOTE2 and NOTE3 near end of file.
'

############################################################################

case $1 in
-h|--help)
    echo "$HELP"
    exit 0
    ;;
# if "--open" option is sent as $1, open file ($2) instead of generating menu
--open)
    open_file "$2"
    echo "$0 : failed to open $2" >&2
    exit # in case exec command fails
    ;;
# if "--recent" option is sent, incorporate "recent files" menu
--recent)
    shift
    output='<openbox_pipe_menu>
'
    if [ -x "$recent_script" ]
    then
        output="${output}<separator label=\"Recently opened...\" />
<menu execute=\"$recent_script\" id=\"recent\" label=\"files\" />
"
    else
        echo "$0 : cannot find executable script $recent_script" >&2
    fi
    ;;
*)
    output='<openbox_pipe_menu>
'
    ;;
esac

path="${1:-$HOME}"  # default starting place is ~, otherwise $1
path="${path%/}"
[ -d "$path" ] || { echo "$0 : $path is not a directory" >&2; exit 1; }

case "$path" in    # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*)
    pathe=$(sed "s/\&/\&amp;/g;s/</\&lt;/g;s/>/\&gt;/g;s/\"/\&quot;/g;s/'/\&apos;/g;" <<XXX
$path
XXX
)
    ;;
*)
    pathe=$path
    ;;
esac

case "$pathe" in
*\&apos\;*)
    pathe_apos=$(sed 's/\&apos;/\&apos;\&quot;\&apos;\&quot;\&apos;/g;'<<XXX
$pathe
XXX
)
    ;;
*)
    pathe_apos=$pathe
    ;;
esac

output="$output<separator label=\"$pathe\" />
<item label=\"Browse here...\">
    <action name=\"Execute\">
        <command>
         &apos;$open_folder_cmd&apos; &apos;$pathe_apos&apos;
        </command>
    </action>
</item>
<separator />
"

unset extra_entries directories_menu files_menu
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
do
    [ -e "$i" ] || continue    # only output code if file exists
    shortname="${i##*/}"
    case $shortname in
    *\&*|*\<*|*\>*|*\"*|*\'*)
        shortnamee=$(sed "s/\&/\&amp;/g;s/</\&lt;/g;s/>/\&gt;/g;s/\"/\&quot;/g;s/'/\&apos;/g;" <<XXX
$shortname
XXX
)
        ;;
    *)
        shortnamee=$shortname
        ;;
    esac
    case $shortnamee in
    *\&apos\;*)
        shortnamee_apos=$(sed 's/\&apos;/\&apos;\&quot;\&apos;\&quot;\&apos;/g;'<<XXX
$shortnamee
XXX
)
        ;;
    *)
        shortnamee_apos=$shortnamee
        ;;
    esac
    case $shortnamee in
    *_*)
        shortnamee_label=$(sed 's/_/__/g;'<<XXX
$shortnamee
XXX
)
        ;;
    *)
        shortnamee_label=$shortnamee
        ;;
    esac
    if [ -d "$i" ]
    then
# NOTE1 If you want directories and files listed together
# change next line [directories_menu="$directories_menu] to read: [files_menu="$files_menu] (there is no final quote)
        directories_menu="$directories_menu
<menu id=\"${pathe_apos}/${shortnamee_apos}\" label=\"$shortnamee_label\" execute=\"&apos;$0&apos; &apos;${pathe_apos}/${shortnamee_apos}&apos;\" />"
    else
        files_menu="$files_menu
<item label=\"$shortnamee_label\">
    <action name=\"Execute\">
        <command>
        &apos;$0&apos; --open &apos;${pathe_apos}/${shortnamee_apos}&apos;
        </command>
    </action>
</item>"
    fi
done

[ -n "$directories_menu" ] && {
# NOTE2 comment out next 2 lines if you don't want "Directories" label
#   output="${output}<separator label=\"Directories\" />
#"
    output="${output}${directories_menu}
"
}
[ -n "$files_menu" ] && {
# NOTE3 comment out next 2 lines if you don't want "Files" label
#   output="${output}<separator label=\"Files\" />
#"
    output="${output}${files_menu}
"
}
output="${output}</openbox_pipe_menu>
"
printf '%s' "$output"
exit
